package com.syezon.wifikey.speed;

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.CornerPathEffect;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Path;
import android.graphics.PathEffect;
import android.graphics.PathMeasure;
import android.graphics.Point;
import android.graphics.Shader;
import android.os.Build;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;

import java.util.ArrayList;
import java.util.List;


public class SpeedChartView extends View {

    public static final String TAG = SpeedChartView.class.getSimpleName();

    /**
     * 图表的线的paint
     */
    private Paint linePaint = new Paint();

    private int colorLine = Color.parseColor("#69E3C2");

    PathEffect pathEffect = new CornerPathEffect(dp2px(5));
    /**
     * 填充的paint
     */
    private Paint fillPaint = new Paint();
    /**
     * x轴（横向）分割线
     */
    private Paint gridPaint = new Paint();
    private int colorGrid = Color.parseColor("#33ffffff");

    /**
     * 绘制曲线的路径
     */
    private Path path = new Path();

    /**
     * 动画相关
     */
    private PathMeasure mPathMeasure;
    private ValueAnimator valueAnimator;
    private float mAnimatorValue;
    private ValueAnimator.AnimatorUpdateListener mUpdateListener;

    /**
     * 数据集合
     */
    private List<SpeedInfo> datas = new ArrayList<>();

    private List<Point> points = new ArrayList<>();

    /**
     * 网格线的间隔
     */
    private int xScaleValue;

    private int yScaleValue;

    private int mPadding;

    /**
     * y轴坐标数
     */
    private static final int ySize = 5;
    /**
     * x轴坐标数
     */
    private static final int xSize = 30;

    /**
     * 是否播放动画
     */
    private boolean playAnim = false;
    /**
     * 默认的动效周期 2s
     */
    private int defaultDuration = 1500;

    /**
     * 选中的value
     */
    private SpeedInfo selectedValue;

    /**
     * 动画是否结束
     */
    private boolean isOver = false;
    /**
     * 是否充满曲线下面的区域
     */
    private boolean isFillArea = true;

    /**
     * 填充区域随曲线一起运动
     */
    private boolean fillAreaHasAnim = true;

    /**
     * 横坐标跟point是否是一对一关系（point有几百个点，但坐标轴只取平均7个，曲线则全部绘制）
     */
    private boolean isOneToOne = true;
    private String xLabels[] = new String[7];

    public SpeedChartView(Context context) {
        this(context, null);
    }

    public SpeedChartView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SpeedChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public SpeedChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context);
    }

    private void init(Context context) {
        linePaint.setAntiAlias(true);
        linePaint.setStyle(Paint.Style.STROKE);
        linePaint.setStrokeJoin(Paint.Join.ROUND);// 笔刷图形样式
        linePaint.setStrokeCap(Paint.Cap.ROUND);// 设置画笔转弯的连接风格
        linePaint.setDither(true);//防抖动
        linePaint.setShader(null);
        linePaint.setStrokeWidth(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2f, getResources().getDisplayMetrics()));
        linePaint.setColor(colorLine);
        linePaint.setPathEffect(pathEffect);

        fillPaint.setAntiAlias(true);
        fillPaint.setStyle(Paint.Style.FILL);
        fillPaint.setStrokeJoin(Paint.Join.ROUND);// 笔刷图形样式
        fillPaint.setStrokeCap(Paint.Cap.ROUND);// 设置画笔转弯的连接风格
        fillPaint.setDither(true);//防抖动
        fillPaint.setStrokeWidth(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2f, getResources().getDisplayMetrics()));
        fillPaint.setColor(colorLine);
        fillPaint.setPathEffect(pathEffect);

        gridPaint.setAntiAlias(true);
        gridPaint.setStyle(Paint.Style.STROKE);
        gridPaint.setStrokeJoin(Paint.Join.ROUND);// 笔刷图形样式
        gridPaint.setStrokeCap(Paint.Cap.ROUND);// 设置画笔转弯的连接风格
        gridPaint.setDither(true);//防抖动
        gridPaint.setShader(null);
        gridPaint.setStrokeWidth(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 0.5f, getResources().getDisplayMetrics()));
        gridPaint.setColor(colorGrid);
    }

    private int dp2px(int dp) {
        return (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics()) + 0.5f);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mPadding = Math.max(
                Math.max(getPaddingLeft(), getPaddingTop()),
                Math.max(getPaddingRight(), getPaddingBottom())
        );
        setPadding(0, 0, 0, 0);
        xScaleValue = yScaleValue = getMeasuredWidth() / xSize;
    }

    public void setCurrentSpeed(int speed) {
        if (speed <= 0) {
            return;
        }
        if (datas.isEmpty()) {
            datas.add(new SpeedInfo(0, 0));
            datas.add(new SpeedInfo(1, speed));
        } else {
            datas.add(new SpeedInfo(datas.size(), speed));
        }
        data2Point();
        initPath();
        initListener();
        initAnimator();
        if (playAnim) {
            valueAnimator.start();
        }
        fillPaint.setShader(new LinearGradient(0, 0, 0, getHeight(), fillPaint.getColor(),
                fillPaint.getColor() & 0x00ffffff, Shader.TileMode.MIRROR));

        invalidate();
    }

    public void setSpeedSmaplList(List<Double> smaplList) {
        if (smaplList == null || smaplList.isEmpty()) {
            return;
        }
        datas.clear();
        datas.add(new SpeedInfo(0, 0));
        for (int i = 0; i < smaplList.size(); i++) {
            datas.add(new SpeedInfo(i + 1, smaplList.get(i)));
        }
        data2Point();
        initPath();
        initListener();
        initAnimator();
        if (playAnim) {
            valueAnimator.start();
        }
        int color = fillPaint.getColor() & 0x00ffffff | 0x3f000000;
        fillPaint.setShader(new LinearGradient(0, 0, 0, getHeight(), color,
                fillPaint.getColor() & 0x00ffffff, Shader.TileMode.MIRROR));
        invalidate();
    }


    public void reset() {
        datas.clear();
        points.clear();
        path.reset();
        invalidate();
    }

    private void data2Point() {
        double maxSpeed = 0;
        for (int i = 0; i < datas.size(); i++) {
            SpeedInfo speedInfo = datas.get(i);
            if (speedInfo.speed > maxSpeed) {
                maxSpeed = speedInfo.speed;
            }
        }
        points.clear();
        for (int i = 0; maxSpeed > 0 && i < datas.size(); i++) {
            SpeedInfo speedInfo = datas.get(i);
            double speed = speedInfo.speed;
            float rate = (float) (speed * 1.0f / maxSpeed);
            int y = getHeight() - (int) ((getHeight() * 0.9f) * rate);
            int x = xScaleValue / 2 + xScaleValue * i;
            points.add(new Point(x, y));
        }
    }

    private void initPath() {
        path.reset();
        if (points.size() > 0) {
            path.moveTo(points.get(points.size() - 1).x, points.get(points.size() - 1).y);
            for (int i = points.size() - 1; i >= 0; i--) {
                path.lineTo(points.get(i).x, points.get(i).y);
            }
            mPathMeasure = new PathMeasure(path, false);
        }
    }

    private void initListener() {
        mUpdateListener = new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mAnimatorValue = (float) animation.getAnimatedValue();
                invalidate();
            }
        };
    }

    private void initAnimator() {
        valueAnimator = ValueAnimator.ofFloat(1, 0).setDuration(defaultDuration);
        valueAnimator.addUpdateListener(mUpdateListener);
        valueAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                isOver = true;
                invalidate();
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));
        for (int i = yScaleValue / 2; i < getHeight(); i = i + yScaleValue) {
            canvas.drawLine(0 + mPadding, i, getWidth() - getPaddingRight(), i, gridPaint);
        }
        for (int i = xScaleValue / 2; i < getWidth(); i = i + xScaleValue) {
            canvas.drawLine(i + mPadding, 0, i + mPadding, getHeight(), gridPaint);
        }
        if (datas == null || datas.size() == 0) {
            return;
        }
//        //绘制曲线图
//        if (playAnim) {
//            Path dst = new Path();
//            //根据动画值从线段总长度不断截取绘制造成动画效果
//            mPathMeasure.getSegment(mPathMeasure.getLength() * mAnimatorValue, mPathMeasure.getLength(), dst, true);
//            canvas.drawPath(dst, linePaint);
////            if (fillAreaHasAnim) {
////                float currX = (points[datas.size() - 1][0] - points[0][0]) * (1 - mAnimatorValue) + points[0][0];
////                if (isFillArea) {
////                    dst.lineTo(points[0][0], bottomY);
////                    dst.lineTo(currX, bottomY);
////                    dst.close();
////                    canvas.drawPath(dst, fillPaint);
////                }
////            }
//        } else {
        canvas.drawPath(path, linePaint);
//        }
        if (isFillArea && !points.isEmpty()) {
            Path pa = new Path(path);
            pa.lineTo(0, getHeight());

            pa.lineTo(points.get(points.size() - 1).x, getHeight());
//            pa.lineTo(xScaleValue / 2 + points.size() * xScaleValue, getHeight());
            pa.close();
            canvas.drawPath(pa, fillPaint);
        }
        if (isOver || !playAnim) {
            if (isFillArea && !points.isEmpty()) {
                Path pa = new Path(path);
                pa.lineTo(0, getHeight());
//                pa.lineTo(xScaleValue / 2 + points.size() * xScaleValue, getHeight());
                pa.lineTo(points.get(points.size() - 1).x, getHeight());
                pa.close();
                canvas.drawPath(pa, fillPaint);
            }
        }
    }

    public SpeedChartView setFillArea(boolean fillArea) {
        isFillArea = fillArea;
        return this;
    }

    public SpeedChartView setGridColor(int color) {
        colorGrid = color;
        invalidate();
        return this;
    }

    public SpeedChartView setLineColor(int color) {
        colorLine = color;
        linePaint.setColor(colorLine);
        fillPaint.setColor(colorLine);
        invalidate();
        return this;
    }

    public SpeedChartView setPlayAnim(boolean playAnim) {
        this.playAnim = playAnim;
        return this;
    }

    public SpeedChartView setFillAreaHasAnim(boolean fillAreaHasAnim) {
        this.fillAreaHasAnim = fillAreaHasAnim;
        return this;
    }

    public static class SpeedInfo {
        public final int index;
        public final double speed;

        public SpeedInfo(int index, double speed) {
            this.index = index;
            this.speed = speed;
        }
    }
}
